/*
@author dracula
 */
package com.duckhunter.bloodbath;

/* import com.com.duckhunter.bloodbath.Clock; */
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.game.GameCanvas;


import java.io.IOException;
import java.util.Random;
import java.util.Timer;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.game.LayerManager;
import javax.microedition.lcdui.game.Sprite;
import javax.microedition.lcdui.game.TiledLayer;

public class DuckHunterCanvas
        extends GameCanvas implements Runnable {

    private volatile Thread thread;
    // the duck image
    private Image duckCenterImg;
    private Sprite duckCenterSprite;
    // tiled background image
    private Image backgroundImg;
    private TiledLayer background;
    private Clock clock;
    // the flag that tells the game to stop
    private boolean stop = false;
    private LayerManager mLayerManager;
    // the duck image coordinates
    private int duckCenterX;
    private int duckCenterY;
    //duck's direction when shot is fired
    private int isDuckRight;
    // the distance to move along the x axis
    private int dx = 2; // X axis
    private int dy = 2; // Y axis
    // the center of the screen
    public final int CENTER_X = getWidth() / 2;
    public final int CENTER_Y = getHeight() / 2;
    // the game boundary - not background boundry
    public static int GAME_WIDTH = 220;
    public static int GAME_HEIGHT = 240;
// the shifted x,y origin of the game (GAME AREA - MIKE)
    public final int GAME_ORIGIN_X = 10; // (getWidth() - (GAME_WIDTH) /2);
    public final int GAME_ORIGIN_Y = 40; // (getHeight() - (GAME_HEIGHT) /2);
// the height of sections below and above the hunters
    public final int SECTION_HEIGHT = 64;
// the base of the game height
    public final int BASE = GAME_ORIGIN_Y + GAME_HEIGHT; /*( - SECTION_HEIGHT; MIKE */

// the max height the hunters can jump
    public final int MAX_HEIGHT = 220;
// lowest hunter can go
    public int boundryAroundDuckY = MAX_HEIGHT - 60;
    public int boundryAroundDuckX = GAME_WIDTH;
// random number generator
    public Random random = new Random();
    private BuckShotSprite buckShotSprite;
    private HunterOneSprite hunterOneSprite;
    private HunterTwoSprite hunterTwoSprite;
    // tracks the no of hunters hit
    public int huntersHit = 0;

    public DuckHunterCanvas() {
        super(true);

        try {

            // create and load the duck image
            // and then center it on screen when
            // the MIDlet starts
            duckCenterImg = Image.createImage("/res/up_duck_mirror.png");
            duckCenterX = CENTER_X;
            duckCenterY = BASE;
            duckCenterSprite = new Sprite(duckCenterImg, 51, 58);
            duckCenterSprite.defineReferencePixel(duckCenterSprite.getWidth() / 2,
                    duckCenterSprite.getHeight());

            duckCenterSprite.setRefPixelPosition(duckCenterX, duckCenterY);

            mLayerManager = new LayerManager();
            mLayerManager.append(duckCenterSprite);

            // position of background on screen
            mLayerManager.append(createBackground());
            background.setPosition(0, 40);

        } catch (IOException ioex) {
            System.err.println(ioex.getMessage());
        }            // create the hunter sprites thread and start it
        try {
            hunterOneSprite = new HunterOneSprite(this);
            mLayerManager.insert(hunterOneSprite, 0);
        } catch (Exception e) {
            System.out.println("Error creating HunterOneSprite.");
            System.out.println(e.getMessage());
        } finally {
        }
        try {
            hunterTwoSprite = new HunterTwoSprite(this);
            mLayerManager.insert(hunterTwoSprite, 0);
        } catch (Exception e) {
            System.out.println("Error creating HunterTwoSprite.");
            System.out.println(e.getMessage());
        } finally {
        }
    }

    // When the canvas is shown, start a thread to run the game loop.
    protected void showNotify() {
        thread = new Thread(this);
        thread.start();
        System.out.println("showNotify");
    }

    protected void hideNotify() {
        System.out.println("hideNotify");
    }

    public Random getRandom() {
        return this.random;
    }

    public void start() {
        Thread runner = new Thread(this);
        runner.start();
    }

    Sprite getDuckCenterSprite() {
        return this.duckCenterSprite;
    }

    // creates the background using TiledLayer
    private TiledLayer createBackground() throws IOException {

        // load the image
        backgroundImg = Image.createImage("/res/new_bkgd_tile.png");

        // create the tiledlayer background
        background = new TiledLayer(12, 20, backgroundImg, 20, 20);

        // array tiles the background image
        int[] cells = {
            1, 3, 7, 5, 1, 3, 7, 5, 1, 3, 1, 3,
            1, 3, 7, 5, 1, 3, 7, 5, 1, 3, 1, 3,
            2, 4, 8, 6, 2, 4, 8, 6, 2, 4, 2, 4,
            2, 4, 8, 6, 2, 4, 8, 6, 2, 4, 2, 4,
            9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
            9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
            9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
            9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
            9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
            9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
            9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
            9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
            9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
            9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
            9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
            9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
            9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
            9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
            10, 12, 10, 12, 10, 12, 10, 12, 10, 12, 10, 12,
            11, 13, 11, 13, 11, 13, 11, 13, 11, 13, 11, 13
        };

        // set the background with the images
        for (int i = 0; i < cells.length; i++) {
            int column = i % 12;
            int row = (i - column) / 20;
            background.setCell(column, row, cells[i]);
        }
        return background;

    }

    public void run() {

        // the graphics object for this canvas
        Graphics g = getGraphics();

        // before going in the loop, start the timer clock with a
        // 30 seconds countdown
        clock = new Clock(60);
        new Timer().schedule(clock, 0, 1000);

        while (!stop) { // infinite loop
            // first verify game state
            verifyGameState();
            // check user's input
            checkUserInput();

            if (buckShotSprite != null) {
                if (isDuckRight == 1) {
                    buckShotSprite.moveR();
                } else if (isDuckRight != 1) {
                    buckShotSprite.moveL();
                }
                if (buckShotSprite.getY() < 40) {
                    mLayerManager.remove(buckShotSprite);
                    buckShotSprite = null;
                }
            }
            this.hunterOneSprite.move();
            this.hunterTwoSprite.move();

            // update screen
            updateGameScreen(getGraphics());

            // and sleep, this controls
            // how fast refresh is done
            try {
                Thread.sleep(50);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
        showGameScore(g);
    }

    private void verifyGameState() {

        if (clock.getTimeLeft() == 0) {
            stop = true;
            return;
        }

        if (hunterOneSprite != null && hunterTwoSprite != null && buckShotSprite != null) {
            if (buckShotSprite.collidesWith(hunterOneSprite, true) == true) {
                huntersHit++;
                this.mLayerManager.remove(hunterOneSprite);
                this.mLayerManager.remove(buckShotSprite);
                // create a new hunter here
                try {
                    hunterOneSprite = new HunterOneSprite(this);
                    this.mLayerManager.insert(hunterOneSprite, 0);
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                }
                buckShotSprite = null;
            } else if (buckShotSprite.collidesWith(hunterTwoSprite, true) == true) {
                huntersHit++;
                this.mLayerManager.remove(hunterTwoSprite);
                this.mLayerManager.remove(buckShotSprite);
                // create a new hunter here
                try {
                    hunterTwoSprite = new HunterTwoSprite(this);
                    this.mLayerManager.insert(hunterTwoSprite, 0);
                } catch (Exception e) {
                    System.out.println(e);
                }
                buckShotSprite = null;
            }
        }
    }

    private void showTimeLeft(Graphics g) {
        // what does the clock say
        int timeLeft = clock.getTimeLeft();
        // if less than 6 seconds left
        // flicker time with red and black
        g.setColor(0xffffff);
        Font font = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_LARGE);
        g.setFont(font);
        if (timeLeft < 11) {
            if ((timeLeft % 2) == 0) {
                g.setColor(0xff0000);
            } else {
                g.setColor(0xffffff);
            }
        }
        // draw the time left string
        g.drawString("Time Left: " + timeLeft + " seconds", 0, 0, 0);
    }

    // atend of game, show score
    private void showGameScore(Graphics g) {
        g.setColor(0x113322);
        g.fillRect( 0, 0, this.getWidth(), 40);
        g.setColor(0xffffff);
        Font font = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_LARGE);
        g.setFont(font);
        String say = "You scored " + getHuntersHit() + " hunters.";
        g.drawString( say,
                CENTER_X, CENTER_Y,
                Graphics.HCENTER | Graphics.BASELINE);
        repaint();
    }

    private void checkUserInput() {
        // get the state of keys
        int keyState = getKeyStates();
        // calculate the position for x axis
        moveDuckAxisX(keyState);
        shoot(keyState);
    }

    private void updateGameScreen(Graphics g) {
        // the next two lines clear the background
        g.setColor(0x113322);
        g.fillRect(0, 0, getWidth(), getHeight());

        // desired positions
        mLayerManager.paint(g, 0, 0);

        // write on screen
        showTimeLeft(g);
        // display graphics
        flushGraphics();
    }

    private void createBuckshotSprite() {
        try {
            if (buckShotSprite == null) {
                buckShotSprite = new BuckShotSprite();
                buckShotSprite.setPosition(duckCenterSprite.getX() + 25, duckCenterSprite.getY());
                mLayerManager.insert(buckShotSprite, 0);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void shoot(int keyState) {
        if ((keyState & FIRE_PRESSED) != 0) {
            if (duckCenterSprite.getFrame() <= 0) {
                isDuckRight = 1;
            } else if (duckCenterSprite.getFrame() > 0) {
                isDuckRight = 0;
            }
            createBuckshotSprite();
        }
    }

    public void moveDuckAxisX(int keyState) {
        int duckLocation = duckCenterSprite.getX();
        // determines which way to move and changes the
        // x coordinate accordingly
        if ((keyState & LEFT_PRESSED) != 0) {
            duckCenterSprite.setFrame(0);
            this.duckCenterSprite.move(-dx, 0);
            if (duckLocation < 15) {
                duckCenterSprite.setRefPixelPosition(GAME_ORIGIN_X + 10, BASE);
                duckCenterSprite.prevFrame();
            }

        } else if ((keyState & RIGHT_PRESSED) != 0) {
            duckCenterSprite.setFrame(1);
            this.duckCenterSprite.move(dx, 0);
            if (duckLocation >= getWidth() - 65) {
                duckCenterSprite.setRefPixelPosition((GAME_WIDTH), BASE);
                duckCenterSprite.setFrame(0);
            }

        }
    }

    // the no of hunters hit
    public int getHuntersHit() {
        return huntersHit;
    }

    public LayerManager getManager() {
        return this.mLayerManager;
    }
}
